package com.theone.sample;//  ┏┓　　　┏┓
//┏┛┻━━━┛┻┓
//┃　　　　　　　┃
//┃　　　━　　　┃
//┃　┳┛　┗┳　┃
//┃　　　　　　　┃
//┃　　　┻　　　┃
//┃　　　　　　　┃
//┗━┓　　　┏━┛
//    ┃　　　┃                  神兽保佑
//    ┃　　　┃                  永无BUG！
//    ┃　　　┗━━━┓
//    ┃　　　　　　　┣┓
//    ┃　　　　　　　┏┛
//    ┗┓┓┏━┳┓┏┛
//      ┃┫┫　┃┫┫
//      ┗┻┛　┗┻┛

import android.app.Activity;
import android.view.View;

import com.theone.sample.annotation.EventType;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author The one
 * @date 2021-09-08 15:06
 * @describe 注入
 * @email 625805189@qq.com
 * @remark
 */
public class InjectUtil {

    public static void injectEvent(Activity activity){
        Class<? extends Activity> activityClass = activity.getClass();
        // 获取类里面所有的方法
        Method[] methods = activityClass.getDeclaredMethods();
        for (Method method:methods){
            // 为了好理解，结合 AnnotationActivity , 这里以 [onClick] 方法为示例讲
            // TODO 获取【onClick】方法上所有的注解
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation:annotations){
                // 注解类型
                Class<? extends Annotation> annotationType = annotation.annotationType();
                // 注解是包含了EventType注解
                if(annotationType.isAnnotationPresent(EventType.class)){
                    // TODO 这里的 【annotationType】 也就是 【OnClick】 注解
                    //  拿到【OnClick注解】上的【EventType注解】
                    EventType eventType = annotationType.getAnnotation(EventType.class);
                    // 拿到注接里面的值 OnClick注解里面写好的
                    Class<?> listenerType = eventType.listenerType();
                    String listenerSetter = eventType.listenerSetter();

                    try {
                        // TODO 拿到 OnClick 注解里的值
                        Method valueMethod = annotationType.getDeclaredMethod("value");
                        // 这里的 'value' 是 【OnClick注解】 里的方法名
                        // 可以为其他的，只不过直接写 value ,使用时不用再另外的指定，详情看【OnClick注解】里和【AnnotationActivity里onClick方法】注释的部分
                        // Method valueMethod = annotationType.getDeclaredMethod("ids");
                        int[] viewIds = (int[])valueMethod.invoke(annotation);

                        method.setAccessible(true);

                        // TODO 动态代理
                        //  相当于把【AnnotationActivity】里的【onClick】方法转移到了
                        //  本应该我们自己实现对【View】设置【点击监听】的【OnClickListener】方法
                        ListenerInvocationHandler<Activity> handler = new ListenerInvocationHandler<>(activity,method);
                        Object listenerProxy = Proxy.newProxyInstance(activity.getClassLoader(), new Class[]{listenerType}, handler);

                        // 遍历注解的值
                        for (int id : viewIds){
                            // 获取当前Activity的View
                            View view = activity.findViewById(id);
                            // 获取指定方法 如：setOnClickListener方法，参数为OnClickListener
                            // getMethod("setOnClickListener", View.OnClickListener.class)
                            Method listener = view.getClass().getMethod(listenerSetter, listenerType);
                            //执行setOnClickListener里面的回调 onClick方法
                            listener.invoke(view,listenerProxy);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 还可能在自定义view注入，所以是泛型： T = Activity/View
     * @param <T>
     */
    static class ListenerInvocationHandler<T> implements InvocationHandler {

        private Method method;
        private T target;

        public ListenerInvocationHandler(T target, Method method) {
            this.target = target;
            this.method = method;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return this.method.invoke(target, args);
        }
    }

}
